package com.cl.blog.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cl.blog.common.Const;
import com.cl.blog.common.RedisHashKey;
import com.cl.blog.document.Ranking;
import com.cl.blog.entity.BContent;
import com.cl.blog.entity.BUser;
import com.cl.blog.entity.BUserFollow;
import com.cl.blog.exception.WebException;
import com.cl.blog.mapper.BContentMapper;
import com.cl.blog.mapper.BContentReviewMapper;
import com.cl.blog.mapper.BUserLikeMapper;
import com.cl.blog.mapper.BUserMapper;
import com.cl.blog.service.*;
import com.cl.blog.util.JwtUtil;
import com.cl.blog.util.RedisUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 付
 * @Date 2024-04-02 18:01
 * @Version 1.0
 * @description 排行榜的业务类
 * @since 1.0
 */
@Service
@Slf4j
public class RankingSerivce {

	private static final String RANKING = RedisHashKey.RANKING.getType();
	private static final String WEEK_RANKING = RedisHashKey.WEEK_RANKING.getType();
	@Autowired
	RedisUtil redisUtil;
	@Autowired
	BUserLikeMapper bUserLikeMapper;
	@Autowired
	BUserMapper bUserMapper;

	@Autowired
	BContentMapper bContentMapper;

	// 收藏表
	@Autowired
	BCollectService bCollectService;

	// 文章评论
	@Autowired
	BContentReviewMapper bContentReviewMapper;
	// 历史观看
	@Autowired
	BHistoryLookService bHistoryLookService;

	//用户关注
	@Autowired
	BUserFollowService bUserFollowService;
	@Autowired
	BUserLikeService bUserLikeService;
	@Autowired
	JwtUtil jwtUtil;

	/**
	 * 获取单个用户的排名信息
	 *
	 * @param userId
	 * @return
	 */
	public Object getUserRanking(Integer userId) {
		Long rank = redisUtil.zRank(RANKING, String.valueOf(userId));
		Long weekRank = redisUtil.zRank(WEEK_RANKING, String.valueOf(userId));
		return MapUtil.builder().put("rank", rank + 1).put("weekRank", weekRank + 1).build();
	}

	public Object getRanking() {
		Set<ZSetOperations.TypedTuple<String>> rank = redisUtil.zRangeWithScores(RANKING, 0, -1);
		Set<ZSetOperations.TypedTuple<String>> weekRank = redisUtil.zRangeWithScores(WEEK_RANKING, 0, -1);

		return MapUtil.builder().put("ranking", rank).put("weekRanking", weekRank).build();
	}

	public Object getRankingWithHome(HttpServletRequest request){

		// 获取当前用户的信息
		String token = request.getHeader("token");
		Claims claim = jwtUtil.getClaimByToken(token, Const.GRADE_USER);
		// 获取关注列表
		List<BUserFollow> follows = bUserFollowService.list(new QueryWrapper<BUserFollow>()
				.eq("user_id", Integer.valueOf(claim.getSubject()))
		);
		// 获取当前用户的关注列表id
		List<Integer> followsIds = follows.stream().map(BUserFollow::getFollowUserId).collect(Collectors.toList());



		Set<ZSetOperations.TypedTuple<String>> rank = redisUtil.zRangeWithScores(RANKING, 0, 9);
		Set<ZSetOperations.TypedTuple<String>> weekRank = redisUtil.zRangeWithScores(WEEK_RANKING, 0, 9);
		List<BUser> ranking = new ArrayList<>();
		List<BUser> weekRanking = new ArrayList<>();

		for (ZSetOperations.TypedTuple<String> typedTuple : rank) {
			// 获取每个排名信息的用户信息
			BUser bUser = bUserMapper.selectById(Integer.valueOf(typedTuple.getValue()));
			if (bUser==null){
				continue;
			}
			if (bUser.getId().equals(Integer.valueOf(claim.getSubject()))){
				boolean b = followsIds.stream().anyMatch(item -> item.equals(Integer.valueOf(claim.getSubject())));
				if (b){
					bUser.setFollow(b);
				}
			}
			bUser.setScore(Math.toIntExact(Math.abs(Math.round(typedTuple.getScore()))));
			// 用户的粉丝数量
			List<BUserFollow> followList = bUserFollowService.list(new QueryWrapper<BUserFollow>()
					.eq("follow_user_id", typedTuple.getValue())
			);
			bUser.setFollowCount((long) followList.size());
			// 获取总点赞量
			Long likeCount = bContentMapper.getLikeCount(Integer.parseInt((String) typedTuple.getValue()));
			bUser.setLikeCount(likeCount);
			ranking.add(bUser);
		}

		for (ZSetOperations.TypedTuple<String> typedTuple : weekRank) {
			// 获取每个排名信息的用户信息
			BUser bUser = bUserMapper.selectById(Integer.valueOf(typedTuple.getValue()));
			if (bUser==null){
				continue;
			}
			bUser.setScore(Math.toIntExact(Math.abs(Math.round(typedTuple.getScore()))));
			// 用户的粉丝数量
			List<BUserFollow> followList = bUserFollowService.list(new QueryWrapper<BUserFollow>()
					.eq("follow_user_id", typedTuple.getValue())
			);
			bUser.setFollowCount((long) followList.size());
			// 获取总点赞量
			Long likeCount = bContentMapper.getLikeCount(Integer.parseInt((String) typedTuple.getValue()));
			bUser.setLikeCount(likeCount);
			weekRanking.add(bUser);
		}
		return MapUtil.builder().put("ranking", ranking).put("weekRanking", weekRanking).build();
	}

	public void addUser(Integer userId) {

	}

	public Object getContent() {
		List<BContent> bContentList = bContentMapper.selectList(new QueryWrapper<BContent>()
				.eq("status", 2)
				.eq("is_delete", 0)
				.orderByDesc("collect")
				.last("limit 10")
		);
		return bContentList;
	}

	@Scheduled(fixedDelay = 12*60*60*1000)
	public Object setRank(){
		log.info("执行了更新排行榜");
		/**
		 * 需要考虑四个要素：关注度、收藏量、点赞量、访问量
		 */
		Map ranking = (Map)getRanking();
		List<DefaultTypedTuple> arrayList1 = new ArrayList<>((LinkedHashSet) ranking.get("ranking"));
		List<DefaultTypedTuple> arrayList2 = new ArrayList<>((LinkedHashSet) ranking.get("weekRanking"));
		Map<String, List<BUser>> ranks = new HashMap<>();
		List<BUser> rank = new ArrayList<>();
		List<BUser> weekRank = new ArrayList<>();

		for (DefaultTypedTuple o : arrayList1) {
			BUser bUser = bUserMapper.selectById((Serializable) o.getValue());
			if (bUser==null){
				continue;
			}
			bUser.setScore(Math.toIntExact(Math.abs(Math.round(o.getScore()))));
			// 用户的粉丝数量
			List<BUserFollow> followList = bUserFollowService.list(new QueryWrapper<BUserFollow>()
					.eq("follow_user_id", o.getValue())
			);
			bUser.setFollowCount((long) followList.size());
			// 获取总点赞量
			Long likeCount = bContentMapper.getLikeCount(Integer.parseInt((String) o.getValue()));
			bUser.setLikeCount(likeCount);

			rank.add(bUser);
		}

		for (DefaultTypedTuple o : arrayList2) {
			BUser bUser = bUserMapper.selectById((Serializable) o.getValue());
			if (bUser==null){
				continue;
			}
			bUser.setScore(Math.toIntExact(Math.abs(Math.round(o.getScore()))));

			// 用户的粉丝数量
			List<BUserFollow> followList = bUserFollowService.list(new QueryWrapper<BUserFollow>()
					.eq("follow_user_id", o.getValue())
			);
			bUser.setFollowCount((long) followList.size());
			// 获取总点赞量
			Long likeCount = bContentMapper.getLikeCount(Integer.parseInt((String) o.getValue()));
			bUser.setLikeCount(likeCount);
			weekRank.add(bUser);
		}

		ranks.put("rank", rank);
		ranks.put("weekRank", weekRank);

		return ranks;
	}

	public Object lazyByRank(Integer start, Integer end) {
		Set<ZSetOperations.TypedTuple<String>> rank = redisUtil.zRangeWithScores(RANKING, start, end);
		List<BUser> ranking = new ArrayList<>();
		Long count = redisUtil.zSize(RANKING);
		if (count<start){
			throw new WebException("抱歉，没有更多数据了");
		}
		for (ZSetOperations.TypedTuple<String> typedTuple : rank) {
			// 获取每个排名信息的用户信息
			BUser bUser = bUserMapper.selectById(Integer.valueOf(typedTuple.getValue()));
			if (bUser==null){
				continue;
			}
			bUser.setScore(Math.toIntExact(Math.abs(Math.round(typedTuple.getScore()))));
			// 用户的粉丝数量
			List<BUserFollow> followList = bUserFollowService.list(new QueryWrapper<BUserFollow>()
					.eq("follow_user_id", typedTuple.getValue())
			);
			bUser.setFollowCount((long) followList.size());
			// 获取总点赞量
			Long likeCount = bContentMapper.getLikeCount(Integer.parseInt((String) typedTuple.getValue()));
			bUser.setLikeCount(likeCount);
			ranking.add(bUser);
		}
		return MapUtil.builder().put("ranking", ranking).put("count",count).build();

	}

	public Object lazyByWeekRank(Integer start, Integer end) {
		Set<ZSetOperations.TypedTuple<String>> weekRank = redisUtil.zRangeWithScores(WEEK_RANKING, start, end);
		List<BUser> weekRanking = new ArrayList<>();
		Long count = redisUtil.zSize(WEEK_RANKING);
		if (count<start){
			throw new WebException("抱歉，没有更多数据了");
		}
		for (ZSetOperations.TypedTuple<String> typedTuple : weekRank) {
			// 获取每个排名信息的用户信息
			BUser bUser = bUserMapper.selectById(Integer.valueOf(typedTuple.getValue()));
			if (bUser==null){
				continue;
			}
			bUser.setScore(Math.toIntExact(Math.abs(Math.round(typedTuple.getScore()))));
			// 用户的粉丝数量
			List<BUserFollow> followList = bUserFollowService.list(new QueryWrapper<BUserFollow>()
					.eq("follow_user_id", typedTuple.getValue())
			);
			bUser.setFollowCount((long) followList.size());
			// 获取总点赞量
			Long likeCount = bContentMapper.getLikeCount(Integer.parseInt((String) typedTuple.getValue()));
			bUser.setLikeCount(likeCount);
			weekRanking.add(bUser);
		}
		return MapUtil.builder().put("weekRanking", weekRanking).build();

	}
}
